#include "app_buffer.h"
#include "log.h"
#include <string.h>
#include <stdlib.h>





/**
 * @brief 缓冲区初始化
 * @param total_size 缓冲区总大小  因为是双缓冲结构 所以总大小为2倍
 * @return 主缓冲区指针
 * 	创建两个缓冲区 放入主缓冲区结构体 返回
 */
buffer_t  *app_buffer_init(int total_size)
{	//主缓冲结构体
	buffer_t *buffer = (buffer_t *)malloc(sizeof(buffer_t));
	if(buffer == NULL)
	{
		log_error("malloc buffer error");
	}
	//子缓冲结构体
	for (int i = 0; i < 2; i++)
	{
		 buffer->sub_buffer[i] = (sub_buffer_t *)malloc(sizeof(sub_buffer_t));
		 buffer->sub_buffer[i]->data=malloc(total_size);
		 buffer->sub_buffer[i]->len=0;
		 buffer->sub_buffer[i]->total_size=total_size;
	}
	// 确定读写职责
	buffer->read_index=0;
	buffer->write_index=1;
	//初始化读锁
	pthread_mutex_init(&buffer->read_lock,NULL);
	pthread_mutex_init(&buffer->swap_lock,NULL);
	return buffer;
}

/**
 * @brief 向缓冲区写入数据
 * @param buffer 主缓冲区指针
 * @param data 写入的数据
 * @param len 写入的数据长度
 * @return 成功 0   失败-1
 * 
 * 1   判断是否可以写入数据 比较写入长度和剩余空间
 * 2   如果可以写入数据  2.1 向尾部拷贝数据 2.2 更新当前数据长度
 * 
 */
int app_buffer_write(buffer_t *buffer, char *data, u_int8_t len)
{
   // 0    取得当前负责写入的缓冲区
   // 加交换锁
   pthread_mutex_lock(&buffer->swap_lock);
   sub_buffer_t *write_sub_buffer=buffer->sub_buffer[buffer->write_index];

   // 1   判断是否可以写入数据 比较写入长度和剩余空间 //总长度-当前使用长度
	int remain_len=write_sub_buffer->total_size-write_sub_buffer->len;
	if (len>remain_len)
	{
		 log_error("当前缓冲区剩余空间不足");
		 return -1;
	}
	// * 2   如果可以写入数据  2.1 向尾部拷贝数据 
	//memcpy(write_sub_buffer->data+write_sub_buffer->len,(char)len,1);//帧头长度
	//帧头长度
	write_sub_buffer->data[write_sub_buffer->len]=len;
	
	memcpy(write_sub_buffer->data+write_sub_buffer->len+1,data,(size_t)len);//数据
	//2.2 更新当前数据长度
	write_sub_buffer->len+=(len+1);
	pthread_mutex_unlock(&buffer->swap_lock);

	return 0;

}


/**
 * @brief 切换缓冲区
 * @param buffer 主缓冲区指针
 * @return 成功 0   失败-1
 * 
 *  
 */
static int app_buffer_swap(buffer_t *buffer)
{	
	 log_debug("切换缓冲区 加交换锁");
	 pthread_mutex_lock(&buffer->swap_lock); 
	 buffer->write_index=buffer->write_index==0?1:0; 
	 buffer->read_index=buffer->read_index==0?1:0;
	 pthread_mutex_unlock(&buffer->swap_lock);
	 return 0;
} 

/**
 * @brief 从缓冲区读取数据
 * @param buffer 主缓冲区指针
 * @param buff 读取数据的容器 （已开辟空间）
 * @param buff_len 读取数据的容器长度
 * @return  实际读取数据的长度
 * 
 * // 1 判断容器是否够放一条数据  比较 容器长度和数据长度
 * // 2 判断当前读缓冲是否为空 要做切换
 * // 3 读取数据  3.1 从缓冲区开头位置读取一条数据 3.2从从缓冲区删除数据 3.3 调整缓冲区长度
 * // 4 如果读缓冲区已空 进行切换 
 */
int app_buffer_read(buffer_t *buffer, char *read_buff, int buff_len)
{
	// A  加锁 因为线程会改变 buffer->read_index
	pthread_mutex_lock(&buffer->read_lock);
    //0  取读缓冲区
   sub_buffer_t *read_sub_buffer=buffer->sub_buffer[buffer->read_index];
   // 1 判断当前读缓冲是否为空 要做切换
	// B
	if(read_sub_buffer->len==0)
	{
		// 切换缓冲区
		app_buffer_swap(buffer);
		// 切换分区后 要重新获取读缓冲区
		 read_sub_buffer=buffer->sub_buffer[buffer->read_index];
		//
		if(read_sub_buffer->len==0)
		{
			log_info("当前数据为空");
			return 0;
		}
	}
   // 2 判断容器是否够放一条数据  比较 容器长度和数据长度
	  int data_len=   read_sub_buffer->data[0]; //要提取数据的帧头长度
	  if(buff_len<data_len)
	  {
		  log_error("容器空间不足");
		  return -1;
	  }
    //C
	// 3 读取数据  3.1 从缓冲区开头位置读取一条数据 3.2从从缓冲区删除数据 3.3 调整缓冲区长度
    memcpy(read_buff,read_sub_buffer->data+1,data_len);
	//3.2从从缓冲区删除数据   参数1 ：要移动到的位置  参数2：要移动的起始位置  参数3：要移动的长度
	memmove(read_sub_buffer->data,read_sub_buffer->data+data_len+1,read_sub_buffer->len-data_len-1);
    //3.3 调整缓冲区长度
	read_sub_buffer->len-=(data_len+1);
   
     // 4 如果读缓冲区已空 进行切换 
	 if(read_sub_buffer->len==0)
	 {
		// 切换缓冲区
		app_buffer_swap(buffer);
	 }
	 pthread_mutex_unlock(&buffer->read_lock);
	 return data_len;

}


// 销毁缓冲区
// 释放子缓冲区数据 在释放主缓冲区
void app_buffer_destroy(buffer_t *buffer)
{
	for (int i = 0; i < 2; i++)
	{	
		free(buffer->sub_buffer[i]->data);
		free(buffer->sub_buffer[i]);
	}
	//释放锁
	pthread_mutex_destroy(&buffer->read_lock);
	pthread_mutex_destroy(&buffer->swap_lock);
    free(buffer);
}